home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / DEMON / DEVELOPER / FREENET / WORKBONE.ARC / Linux / WBone / WorkBone-0.1 / hardware.c < prev    next >
C/C++ Source or Header  |  1993-12-08  |  16KB  |  745 lines

  1. #define load() /* nothing */
  2.  
  3. /*
  4.  * @(#)hardware.c    1.12    12/17/92
  5.  *
  6.  * Get information about a CD.
  7.  */
  8. #ifdef BOZO 
  9. static char *ident = "@(#)hardware.c    1.12 12/17/92";
  10. #endif
  11.  
  12. void strmcpy (char **t, char *s);
  13.  
  14. #include <errno.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <unistd.h>
  18. #include <sys/types.h>
  19. #include <sys/ioctl.h>
  20. #include <fcntl.h>
  21. #include <sys/param.h>
  22. #include <sys/stat.h>
  23. #include <sys/time.h>
  24. #    ifdef linux
  25. #     include <linux/cdrom.h>
  26. #    else
  27. #     include <sundev/srreg.h>
  28. #    endif /* linux */
  29. #include "struct.h"
  30.  
  31.  
  32. void *malloc();
  33. char *strchr();
  34.  
  35. extern struct play *playlist;
  36. extern struct cdinfo thiscd, *cd;
  37.  
  38. int    cd_fd = -1;
  39.  
  40. /*
  41.  * The minimum volume setting for the Sun and DEC CD-ROMs is 128 but for other
  42.  * machines this might not be the case.
  43.  */
  44. int    min_volume = 128;
  45. int    max_volume = 255;
  46.  
  47. # ifdef linux
  48. char    *cd_device = "/dev/cdrom\0";
  49. # else
  50. char    *cd_device = "/dev/rsr0\0";
  51. # endif
  52.  
  53. extern int cur_track, cur_index, cur_lasttrack, cur_firsttrack, cur_pos_abs,    
  54.     cur_frame, cur_pos_rel, cur_tracklen, cur_cdlen, cur_ntracks,    
  55.     cur_nsections, cur_cdmode, cur_listno, cur_stopmode, exit_on_eject,
  56.     cur_balance;
  57. extern char *cur_artist, *cur_cdname, *cur_trackname;
  58. extern char    cur_contd, cur_avoid;
  59. /*
  60.  * read_toc()
  61.  *
  62.  * Read the table of contents from the CD.  Return a pointer to a cdinfo
  63.  * struct containing the relevant information (minus artist/cdname/etc.)
  64.  * This is a static struct.  Returns NULL if there was an error.
  65.  *
  66.  * XXX allocates one trackinfo too many.
  67.  */
  68.  
  69. struct cdinfo *
  70. read_toc()
  71. {
  72.     struct playlist        *l;
  73.     struct cdrom_tochdr    hdr;
  74.     struct cdrom_tocentry    entry;
  75.     int            i, pos;
  76.  
  77.     if (cd_fd < 0)
  78.         return(NULL);
  79.  
  80.     if (ioctl(cd_fd, CDROMREADTOCHDR, &hdr))
  81.     {
  82.         perror("readtochdr");
  83.         return (NULL);
  84.     }
  85.  
  86.     thiscd.artist[0] = thiscd.cdname[0] = '\0';
  87.     thiscd.whichdb = thiscd.otherrc = thiscd.otherdb = NULL;
  88.     thiscd.length = 0;
  89.     thiscd.autoplay = thiscd.playmode = thiscd.volume = 0;
  90.     thiscd.ntracks = hdr.cdth_trk1;
  91.  
  92.     if (thiscd.lists != NULL)
  93.     {
  94.         for (l = thiscd.lists; l->name != NULL; l++)
  95.         {
  96.             free(l->name);
  97.             free(l->list);
  98.         }
  99.         free(thiscd.lists);
  100.         thiscd.lists = NULL;
  101.     }
  102.  
  103.     if (thiscd.trk != NULL)
  104.         free(thiscd.trk);
  105.  
  106.     thiscd.trk = malloc((thiscd.ntracks + 1) * sizeof(struct trackinfo));
  107.     if (thiscd.trk == NULL)
  108.     {
  109.         perror("malloc");
  110.         return (NULL);
  111.     }
  112.     for (i = 0; i <= thiscd.ntracks; i++)
  113.     {
  114.         if (i == thiscd.ntracks)
  115.             entry.cdte_track = CDROM_LEADOUT;
  116.         else
  117.             entry.cdte_track = i + 1;
  118.         entry.cdte_format = CDROM_MSF;
  119.         if (ioctl(cd_fd, CDROMREADTOCENTRY, &entry))
  120.         {
  121.             perror("tocentry read");
  122.             return (NULL);
  123.         }
  124.  
  125.         thiscd.trk[i].data =
  126.         thiscd.trk[i].avoid = entry.cdte_ctrl & CDROM_DATA_TRACK ?
  127.             1 : 0;
  128.         thiscd.trk[i].length = entry.cdte_addr.msf.minute * 60 +
  129.                 entry.cdte_addr.msf.second;
  130.         thiscd.trk[i].start = thiscd.trk[i].length * 75 +
  131.                 entry.cdte_addr.msf.frame;
  132.         thiscd.trk[i].songname = thiscd.trk[i].otherrc =
  133.         thiscd.trk[i].otherdb = NULL;
  134.         thiscd.trk[i].contd = 0;
  135.         thiscd.trk[i].volume = 0;
  136.         thiscd.trk[i].track = i + 1;
  137.         thiscd.trk[i].section = 0;
  138.     }
  139.  
  140. /* Now compute actual track lengths. */
  141.     pos = thiscd.trk[0].length;
  142.  
  143.     for (i = 0; i < thiscd.ntracks; i++)
  144.     {
  145.         thiscd.trk[i].length = thiscd.trk[i+1].length - pos;
  146.         pos = thiscd.trk[i+1].length;
  147.         if (thiscd.trk[i].data)
  148.             thiscd.trk[i].length = (thiscd.trk[i + 1].start -
  149.                 thiscd.trk[i].start) * 2;
  150.         if (thiscd.trk[i].avoid)
  151.             strmcpy(&thiscd.trk[i].songname, "DATA TRACK");
  152.     }
  153.  
  154.     thiscd.length = thiscd.trk[thiscd.ntracks].length;
  155.  
  156.     return (&thiscd);
  157. }
  158.  
  159. /*
  160.  * cd_status()
  161.  *
  162.  * Return values:
  163.  *
  164.  *    0    No CD in drive.
  165.  *    1    CD in drive.
  166.  *    2    CD has just been inserted (TOC has been read)
  167.  *    3    CD has just been removed
  168.  *
  169.  * Updates cur_track, cur_pos_rel, cur_pos_abs and other variables.
  170.  */
  171. int
  172. cd_status()
  173. {
  174.     char                realname[MAXPATHLEN];
  175.     static int            warned = 0;
  176.     struct cdrom_subchnl        sc;
  177.  
  178.     int                ret = 1;
  179.  
  180.     if (cd_fd < 0)
  181.     {
  182.  
  183.         if ((cd_fd = open(cd_device, 0)) < 0)
  184.         {
  185.  
  186.             if (errno == EACCES)
  187.             {
  188.                 if (!warned)
  189.                 {
  190.                     strcpy(realname, cd_device);
  191.  
  192.                     fprintf(stderr,
  193.         "As root, please run\n\nchmod 666 %s\n\n%s\n", realname,
  194.         "to give yourself permission to access the CD-ROM device.");
  195.                     warned++;
  196.                 }
  197.             }
  198.             else if (errno != ENXIO)
  199.             {
  200.                 perror(cd_device);
  201.                 if (thiscd.trk != NULL)
  202.                     free(thiscd.trk);
  203.                 exit(1);
  204.             }
  205.             return (0);
  206.         }
  207.         cur_cdmode = 5;
  208.     }
  209.  
  210.     if (warned)
  211.     {
  212.         warned = 0;
  213.         fprintf(stderr, "Thank you.\n");
  214.     }
  215.  
  216.     sc.cdsc_format = CDROM_MSF;
  217.  
  218.     if (ioctl(cd_fd, CDROMSUBCHNL, &sc))
  219.     {
  220.         cur_cdmode = 5;
  221.         cur_track = -1;
  222.         cur_cdlen = cur_tracklen = 1;
  223.         cur_pos_abs = cur_pos_rel = cur_frame = 0;
  224.  
  225.         if (exit_on_eject)
  226.             exit(0);
  227.  
  228.         return (0);
  229.     }
  230.  
  231.     if (cur_cdmode == 5)    /* CD has been ejected */
  232.     {
  233.         cur_pos_rel = cur_pos_abs = cur_frame = 0;
  234.  
  235.         if ((cd = read_toc()) == NULL) 
  236.         {
  237.             close(cd_fd);
  238.             cd_fd = -1;
  239.             if (exit_on_eject)
  240.                 exit(0);
  241.             else
  242.                 return (0);
  243.         }
  244.         cur_nsections = 0;
  245.         cur_ntracks = cd->ntracks;
  246.         cur_cdlen = cd->length;
  247.         load();
  248.         cur_artist = cd->artist;
  249.         cur_cdname = cd->cdname;
  250.         cur_cdmode = 4;
  251.         ret = 2;
  252.     }
  253.  
  254.     switch (sc.cdsc_audiostatus) {
  255.     case CDROM_AUDIO_PLAY:
  256.         cur_cdmode = 1;
  257. dopos:
  258.         cur_pos_abs = sc.cdsc_absaddr.msf.minute * 60 +
  259.             sc.cdsc_absaddr.msf.second;
  260.         cur_frame = cur_pos_abs * 75 + sc.cdsc_absaddr.msf.frame;
  261.  
  262.         /* Only look up the current track number if necessary. */
  263.         if (cur_track < 1 || cur_frame < cd->trk[cur_track-1].start ||
  264.                 cur_frame >= (cur_track >= cur_ntracks ?
  265.                 (cur_cdlen + 1) * 75 :
  266.                 cd->trk[cur_track].start))
  267.         {
  268.             cur_track = 0;
  269.             while (cur_track < cur_ntracks && cur_frame >=
  270.                     cd->trk[cur_track].start)
  271.                 cur_track++;
  272.         }
  273.         if (cur_track >= 1 && sc.cdsc_trk > cd->trk[cur_track-1].track)
  274.             cur_track++;
  275.  
  276.         cur_index = sc.cdsc_ind;
  277. doall:
  278.         if (cur_track >= 1 && cur_track <= cur_ntracks)
  279.         {
  280.             cur_trackname = cd->trk[cur_track-1].songname;
  281.             cur_avoid = cd->trk[cur_track-1].avoid;
  282.             cur_contd = cd->trk[cur_track-1].contd;
  283.             cur_pos_rel = (cur_frame -
  284.                 cd->trk[cur_track-1].start) / 75;
  285.             if (cur_pos_rel < 0)
  286.                 cur_pos_rel = -cur_pos_rel;
  287.         }
  288.  
  289.         /* note: workbone requires playlist == NULL always! */        
  290.         if (playlist != NULL && playlist[0].start)
  291.         {
  292.             cur_pos_abs -= cd->trk[playlist[cur_listno-1].
  293.                 start - 1].start / 75;
  294.             cur_pos_abs += playlist[cur_listno-1].starttime;
  295.         }
  296.         if (cur_pos_abs < 0)
  297.             cur_pos_abs = cur_frame = 0;
  298.  
  299.         if (cur_track < 1)
  300.             cur_tracklen = cd->length;
  301.         else
  302.             cur_tracklen = cd->trk[cur_track-1].length;
  303.         break;
  304.  
  305.     case CDROM_AUDIO_PAUSED:
  306.         if (cur_cdmode == 1 || cur_cdmode == 3)
  307.         {
  308.             cur_cdmode = 3;
  309.             goto dopos;
  310.         }
  311.         else
  312.             cur_cdmode = 4;
  313.         goto doall;
  314.  
  315.     case CDROM_AUDIO_COMPLETED:
  316.         cur_cdmode = 0;        /* waiting for next track. */
  317.         break;
  318.  
  319.     case CDROM_AUDIO_NO_STATUS:
  320.         cur_cdmode = 4;
  321.         cur_lasttrack = cur_firsttrack = -1;
  322.         goto doall;
  323.     }
  324.     return (ret);
  325. }
  326. #ifdef BOZO
  327. /*
  328.  * scale_volume(vol, max)
  329.  *
  330.  * Return a volume value suitable for passing to the CD-ROM drive.  "vol"
  331.  * is a volume slider setting; "max" is the slider's maximum value.
  332.  *
  333.  * On Sun and DEC CD-ROM drives, the amount of sound coming out the jack
  334.  * increases much faster toward the top end of the volume scale than it
  335.  * does at the bottom.  To make up for this, we make the volume scale look
  336.  * sort of logarithmic (actually an upside-down inverse square curve) so
  337.  * that the volume value passed to the drive changes less and less as you
  338.  * approach the maximum slider setting.  The actual formula looks like
  339.  *
  340.  *     (max^2 - (max - vol)^2) * (max_volume - min_volume)
  341.  * v = --------------------------------------------------- + min_volume
  342.  *                           max^2
  343.  *
  344.  * If your system's volume settings aren't broken in this way, something
  345.  * like the following should work:
  346.  *
  347.  *    return ((vol * (max_volume - min_volume)) / max + min_volume);
  348.  */
  349. scale_volume(vol, max)
  350.     int    vol, max;
  351. {
  352.     return ((max * max - (max - vol) * (max - vol)) *
  353.         (max_volume - min_volume) / (max * max) + min_volume);
  354. }
  355.  
  356. /*
  357.  * unscale_volume(cd_vol, max)
  358.  *
  359.  * Given a value between min_volume and max_volume, return the volume slider
  360.  * value needed to achieve that value.
  361.  *
  362.  * Rather than perform floating-point calculations to reverse the above
  363.  * formula, we simply do a binary search of scale_volume()'s return values.
  364.  */
  365. unscale_volume(cd_vol, max)
  366.     int    cd_vol, max;
  367. {
  368.     int    vol, incr, scaled;
  369.  
  370.     for (vol = max / 2, incr = max / 4 + 1; incr; incr /= 2)
  371.     {
  372.         scaled = scale_volume(vol, max);
  373.         if (cd_vol == scaled)
  374.             break;
  375.         if (cd_vol < scaled)
  376.             vol -= incr;
  377.         else
  378.             vol += incr;
  379.     }
  380.     
  381.     if (vol < 0)
  382.         vol = 0;
  383.     else if (vol > max)
  384.         vol = max;
  385.  
  386.     return (vol);
  387. }
  388.  
  389. /*
  390.  * cd_volume(vol, bal, max)
  391.  *
  392.  * Set the volume levels.  "vol" and "bal" are the volume and balance knob
  393.  * settings, respectively.  "max" is the maximum value of the volume knob
  394.  * (the balance knob is assumed to always go from 0 to 20.)
  395.  */
  396. void
  397. cd_volume(vol, bal, max)
  398.     int    vol, bal, max;
  399. {
  400.     int    left, right;
  401.     struct cdrom_volctrl v;
  402.  
  403. /*
  404.  * Set "left" and "right" to volume-slider values accounting for the
  405.  * balance setting.
  406.  *
  407.  * XXX - the maximum volume setting is assumed to be in the 20-30 range.
  408.  */
  409.     if (bal < 9)
  410.         right = vol - (9 - bal) * 2;
  411.     else
  412.         right = vol;
  413.     if (bal > 11)
  414.         left = vol - (bal - 11) * 2;
  415.     else
  416.         left = vol;
  417.  
  418. /* Adjust the volume to make up for the CD-ROM drive's weirdness. */
  419.     left = scale_volume(left, max);
  420.     right = scale_volume(right, max);
  421.  
  422.     v.channel0 = left < 0 ? 0 : left > 255 ? 255 : left;
  423.     v.channel1 = right < 0 ? 0 : right > 255 ? 255 : right;
  424.     if (cd_fd >= 0)
  425.         (void) ioctl(cd_fd, CDROMVOLCTRL, &v);
  426. }
  427. #endif /* BOZO */
  428. /*
  429.  * pause_cd()
  430.  *
  431.  * Pause the CD, if it's in play mode.  If it's already paused, go back to
  432.  * play mode.
  433.  */
  434. void
  435. pause_cd()
  436. {
  437.     if (cd_fd < 0)    /* do nothing if there's no CD! */
  438.         return;
  439.  
  440.     switch (cur_cdmode) {
  441.     case 1:        /* playing */
  442.         cur_cdmode = 3;
  443.         ioctl(cd_fd, CDROMPAUSE);
  444.         break;
  445.     case 3:        /* paused */
  446.         cur_cdmode = 1;
  447.         ioctl(cd_fd, CDROMRESUME);
  448.     }
  449. }
  450.  
  451. /*
  452.  * stop_cd()
  453.  *
  454.  * Stop the CD if it's not already stopped.
  455.  */
  456. void
  457. stop_cd()
  458. {
  459.     if (cd_fd < 0)
  460.         return;
  461.  
  462.     if (cur_cdmode != 4)
  463.     {
  464.         cur_lasttrack = cur_firsttrack = -1;
  465.         cur_cdmode = 4;
  466.         ioctl(cd_fd, CDROMSTOP);
  467.         cur_track = 1;
  468.     }
  469. }
  470.  
  471. /*
  472.  * play_chunk(start, end)
  473.  *
  474.  * Play the CD from one position to another (both in frames.)
  475.  */
  476. void
  477. play_chunk(start, end)
  478.     int start, end;
  479. {
  480.     struct cdrom_msf        msf;
  481.  
  482.     if (cd == NULL || cd_fd < 0)
  483.         return;
  484.  
  485.     end--;
  486.     if (start >= end)
  487.         start = end-1;
  488.  
  489.     msf.cdmsf_min0 = start / (60*75);
  490.     msf.cdmsf_sec0 = (start % (60*75)) / 75;
  491.     msf.cdmsf_frame0 = start % 75;
  492.     msf.cdmsf_min1 = end / (60*75);
  493.     msf.cdmsf_sec1 = (end % (60*75)) / 75;
  494.     msf.cdmsf_frame1 = end % 75;
  495.  
  496.     if (ioctl(cd_fd, CDROMSTART))
  497.     {
  498.         perror("CDROMSTART");
  499.         return;
  500.     }
  501.     if (ioctl(cd_fd, CDROMPLAYMSF, &msf))
  502.     {
  503.         printf("play(%d,%d)\n",start,end);
  504.         printf("msf = %d:%d:%d %d:%d:%d\n",
  505.             msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0,
  506.             msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1);
  507.         perror("CDROMPLAYMSF");
  508.         return;
  509.     }
  510. }
  511.  
  512. /*
  513.  * play_cd(starttrack, pos, endtrack)
  514.  *
  515.  * Start playing the CD or jump to a new position.  "pos" is in seconds,
  516.  * relative to start of track.
  517.  */
  518. void
  519. play_cd(start, pos, end)
  520. int start, pos, end;
  521. {
  522.  
  523.     if (cd == NULL || cd_fd < 0)
  524.         return;
  525.  
  526.     cur_firsttrack = start;
  527.     start--;
  528.     end--;
  529.     cur_lasttrack = end;
  530.  
  531.     play_chunk(cd->trk[start].start + pos * 75, end >= cur_ntracks ?
  532.         cur_cdlen * 75 : cd->trk[end].start - 1);
  533. }
  534.  
  535. #ifdef BOZO
  536. /*
  537.  * Set the offset into the current track and play.  -1 means end of track
  538.  * (i.e., go to next track.)
  539.  */
  540. void
  541. play_from_pos(pos)
  542.     int    pos;
  543. {
  544.     if (pos == -1)
  545.         if (cd)
  546.             pos = cd->trk[cur_track - 1].length - 1;
  547.     if (cur_cdmode == 1)
  548.         play_cd(cur_track, pos, playlist[cur_listno-1].end);
  549. }
  550. #endif
  551.  
  552. /*
  553.  * Eject the current CD, if there is one, and set the mode to 5.
  554.  *
  555.  * Returns 0 on success, 1 if the CD couldn't be ejected, or 2 if the
  556.  * CD contains a mounted filesystem.
  557.  */
  558. int 
  559. eject_cd()
  560. {
  561.     struct stat    stbuf;
  562.     struct ustat    ust;
  563.  
  564.     if (cur_cdmode == 5)        /* Already ejected! */
  565.         return (0);
  566.  
  567.     if (fstat(cd_fd, &stbuf) != 0)
  568.     {
  569.         perror("fstat");
  570.         return (1);
  571.     }
  572.  
  573.     /* Is this a mounted filesystem? */
  574.     if (ustat(stbuf.st_rdev, &ust) == 0)
  575.         return (2);
  576.  
  577.     if (ioctl(cd_fd, CDROMEJECT))
  578.     {
  579.         perror("CDEJECT");
  580.         return (1);
  581.     }
  582.  
  583.     if (exit_on_eject)
  584.         exit(0);
  585.  
  586.     cur_track = -1;
  587.     cur_cdlen = cur_tracklen = 1;
  588.     cur_pos_abs = cur_pos_rel = cur_frame = 0;
  589.     cur_cdmode = 5;
  590.  
  591.     return (0);
  592. }
  593. #ifdef BOZO
  594. /* Try to keep the CD open all the time.  This is run in a subprocess. */
  595. void
  596. keep_cd_open()
  597. {
  598.     int    fd;
  599.     struct flock    fl;
  600.     extern    end;
  601.  
  602.     for (fd = 0; fd < 256; fd++)
  603.         close(fd);
  604.  
  605.     if (fork())
  606.         exit(0);
  607.  
  608.     if ((fd = open("/tmp/cd.lock", O_RDWR | O_CREAT, 0666)) < 0)
  609.         exit(0);
  610.     fl.l_type = F_WRLCK;
  611.     fl.l_whence = 0;
  612.     fl.l_start = 0;
  613.     fl.l_len = 0;
  614.     if (fcntl(fd, F_SETLK, &fl) < 0)
  615.         exit(0);
  616.  
  617.     if (open(cd_device, 0) >= 0)
  618.     {
  619.         brk(&end);
  620.         pause();
  621.     }
  622.  
  623.     exit(0);
  624. }
  625.  
  626. /*
  627.  * find_trkind(track, index)
  628.  *
  629.  * Start playing at a particular track and index, optionally using a particular
  630.  * frame as a starting position.  Returns a frame number near the start of the
  631.  * index mark if successful, 0 if the track/index didn't exist.
  632.  *
  633.  * This is made significantly more tedious (though probably easier to port)
  634.  * by the fact that CDROMPLAYTRKIND doesn't work as advertised.  The routine
  635.  * does a binary search of the track, terminating when the interval gets to
  636.  * around 10 frames or when the next track is encountered, at which point
  637.  * it's a fair bet the index in question doesn't exist.
  638.  */
  639. find_trkind(track, index, start)
  640.     int    track, index, start;
  641. {
  642.     int    top = 0, bottom, current, interval, ret = 0, i;
  643.  
  644.     if (cd == NULL || cd_fd < 0)
  645.         return;
  646.  
  647.     for (i = 0; i < cur_ntracks; i++)
  648.         if (cd->trk[i].track == track)
  649.             break;
  650.     bottom = cd->trk[i].start;
  651.  
  652.     for (; i < cur_ntracks; i++)
  653.         if (cd->trk[i].track > track)
  654.             break;
  655.  
  656.     top = i == cur_ntracks ? (cd->length - 1) * 75 : cd->trk[i].start;
  657.  
  658.     if (start > bottom && start < top)
  659.         bottom = start;
  660.  
  661.     current = (top + bottom) / 2;
  662.     interval = (top - bottom) / 4;
  663.  
  664.     do {
  665.         play_chunk(current, current + 75);
  666.  
  667.         if (cd_status() != 1)
  668.             return (0);
  669.         while (cur_frame < current)
  670.             if (cd_status() != 1 || cur_cdmode != 1)
  671.                 return (0);
  672.             else
  673.                 susleep(1);
  674.  
  675.         if (cd->trk[cur_track - 1].track > track)
  676.             break;
  677.  
  678.         if (cur_index >= index)
  679.         {
  680.             ret = current;
  681.             current -= interval;
  682.         }
  683.         else
  684.             current += interval;
  685.         interval /= 2;
  686.     } while (interval > 2);
  687.  
  688.     return (ret);
  689. }
  690.  
  691. /*
  692.  * Simulate usleep() using select().
  693.  */
  694. susleep(usec)
  695.     int    usec;
  696. {
  697.     struct timeval    tv;
  698.  
  699.     timerclear(&tv);
  700.     tv.tv_sec = usec / 1000000;
  701.     tv.tv_usec = usec % 1000000;
  702.     return (select(0, NULL, NULL, NULL, &tv));
  703. }
  704. /*
  705.  * Read the initial volume from the drive, if available.  Set cur_balance to
  706.  * the balance level (0-20, 10=centered) and return the proper setting for
  707.  * the volume knob.
  708.  *
  709.  * "max" is the maximum value of the volume knob.
  710.  */
  711. read_initial_volume(max)
  712.     int max;
  713. {
  714.     int    left, right;
  715.  
  716.     /* Suns can't read the volume; oh well */
  717.     left = right = 255;
  718.  
  719.     left = unscale_volume(left, max);
  720.     right = unscale_volume(right, max);
  721.  
  722.     if (left < right)
  723.     {
  724.         cur_balance = (right - left) / 2 + 11;
  725.         if (cur_balance > 20)
  726.             cur_balance = 20;
  727.  
  728.         return (right);
  729.     }
  730.     else if (left == right)
  731.     {
  732.         cur_balance = 10;
  733.         return (left);
  734.     }
  735.     else
  736.     {
  737.         cur_balance = (right - left) / 2 + 9;
  738.         if (cur_balance < 0)
  739.             cur_balance = 0;
  740.  
  741.         return (left);
  742.     }
  743. }
  744. #endif
  745.